package leetcode.concurrency;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 交替打印FooBar
 * 以下几种方式都行 其中 ReentrantLock自己写出来的,其他2个参考别人的
 * @author jiangwz
 * @create 2019/11/6.
 */
public class Q1115 {

    public static void main(String[] args) throws InterruptedException {
        FooBar fooBar = new FooBar(1);

        new Thread(() -> {
            try {
                fooBar.bar(() -> {
                    System.out.println("bar");
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "thread-name").start();

        new Thread(() -> {
            try {
                fooBar.foo(() -> {
                    System.out.print("foo");
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "thread-name1").start();

    }


}


class FooBar {


    private int n;

    public FooBar(int n) {
        this.n = n;
    }

    ReentrantLock lock = new ReentrantLock(true);
    Condition foo = lock.newCondition();
    Condition bar = lock.newCondition();
    volatile boolean firstA = false;

    public void foo(Runnable printFoo) throws InterruptedException {
        while (!firstA){
            Thread.yield();
        }
        lock.lock();
        try {

            for (int i = 0; i < n; i++) {
                printFoo.run();
                bar.signal();
                foo.await();
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            // 必须要在finally 里面释放锁,否则leetcode 编译不过
            lock.unlock();
        }


    }
    public void bar(Runnable printBar) throws InterruptedException {
        lock.lock();
        try {
            for (int i = 0; i < n; i++) {
                firstA = true;
                bar.await();
                printBar.run();
                foo.signal();
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }


    }


//    BlockingQueue<Integer> fooQueue = new LinkedBlockingQueue<>();
//    BlockingQueue<Integer> barQueue = new LinkedBlockingQueue<>();
//
//    public void foo(Runnable printFoo) throws InterruptedException {
//        for (int i = 0; i < n; i++) {
//            printFoo.run();
//            barQueue.add(1);
//            fooQueue.take();
//        }
//    }
//    public void bar(Runnable printBar) throws InterruptedException {
//        for (int i = 0; i < n; i++) {
//            barQueue.take();
//            printBar.run();
//            fooQueue.add(1);
//        }
//    }


//    java.util.concurrent.Semaphore semaphoreFoo = new java.util.concurrent.Semaphore(0);
//    java.util.concurrent.Semaphore semaphoreBar = new java.util.concurrent.Semaphore(0);

//    public void foo(Runnable printFoo) throws InterruptedException {
//        for (int i = 0; i < n; i++) {
//            printFoo.run();
//            //由于下面阻塞了，所以这里变为0，下面的方法就能继续执行
//            semaphoreBar.release();
//            //这里让他等一会，等到bar()执行完
//            semaphoreFoo.acquire();
//        }
//    }
//    public void bar(Runnable printBar) throws InterruptedException {
//        for (int i = 0; i < n; i++) {
//            // 进来先变为1，就会等上面的release()使他变为0，才进行，所以肯定在foo之后。
//            semaphoreBar.acquire();
//            printBar.run();
//            //bar()执行完了，就让foo()继续。
//            semaphoreFoo.release();
//        }
//    }
}